<?php
/**
 * supply image upload and resize function.
 *
 * @package SGN_Core
 * @version $Id: Upload.php 1437 2012-03-16 10:44:10Z nhudt $
 * @author $Author: nhudt $
 *
 */
class SGN_Upload
{
	/*
	 * adapter to recieve file.
	 * 
	 * @var Zend_File_Transfer_Adapter_Http
	 */
	var $adapter = null;
	
	/*
	 * Indicate whether to rename file or raise error if the name has already exist.
	 * 
	 * @default false
	 * 
	 * @var boolean
	 */
	var $renameIfDuplicate = false;
	
	
	/*
	 * Self property to store itself.
	 * 
	 * @var SGN_Upload
	 */
	static $_self;
	
	public function test()
	{
		return "success";
	}
	
	/**
     *
     * Constructor
     *
     */
    function __construct()
    {
        $this->adapter = $this->createFileTransferAdapter();
        $this->resetDefaultValidators();
    }
    
    public static function factory()
    {
    	if(self::$_self)
    		return self::$_self;
    	self::$_self = new self();
    	return self::$_self;
    }
    
    /*
     * create Zend File Transfer Adapter
     * 
     * @return Zend_File_Transfer_Adapter_Http
     */
	protected function createFileTransferAdapter()
    {
    	//$config = SGN_Application::getConfig('sgn', 'settings', 'upload');
    	
    	$adapter = new Zend_File_Transfer_Adapter_Http();
    	
//         $translator = new Zend_Translate(array(
//                                             'adapter' => 'array', 
//                                             'content' => ROOT_PATH . '/' . $config->validator->messagefile, 
//                                             'locale' => 'vi', 
//                                             'scan' => Zend_Translate::LOCALE_FILENAME,
//         ));
        
//         $adapter->setTranslator($translator);
        
        return $adapter;
    }
    
    /*
     * Reset all validators to default state.
     * 
     * @return void
     */
    public function resetDefaultValidators()
    {
    	$this->clearValidators();
    	
    	//add extension Validator.
        $extensionValidator = new Zend_Validate_File_Extension('jpg,gif,png');
        $this->adapter->addValidator($extensionValidator, false);
        //add Count validator
        $countValidator = new Zend_Validate_File_Count(1);
        $this->adapter->addValidator($countValidator, false, 1);
        //add Size validator
        $sizeValidator = new Zend_Validate_File_Size('5MB');
        $this->adapter->addValidator($sizeValidator, false);
    }
    
    /*
     * Start uploading file.
     * 
     * @return true if success; otherwise return false;
     */
    public function receive($controlName, $path, $newName = '')
    {
    	if($newName){
    		$this->adapter->addFilter('Rename', array('target' => $path . $newName));
    	} else {
    		$this->adapter->addFilter('Rename', array('target' => $path . $this->getEncodedFileName($controlName)));
    	}
        //add Exist validator
        $this->adapter->removeValidator('Zend_Validate_File_NotExists');
        
        $notExistValidator = new Zend_Validate_File_NotExists($path);
        $this->adapter->addValidator($notExistValidator, false, $path);
        
    	if(!$this->adapter->isValid()){
    		return false;
    	}
    	
    	$this->adapter->receive();
    	return true;
    }
    
    public static function checkFolder($path)
    {
        try{
        	if(file_exists($path)){
        		if(!is_dir($path)){
        			try {
        				unlink($path);
        				if(!mkdir($path, 0777)) {
        					return false;
        				}
                		if(!chmod($path, 0777)){
                    	    return false;
                    	}
        			} catch (Exception $ex){
        				return false;
        			}
        		}
        	} else {
        		if (!mkdir($path, 0777)){
        			return false;
        		}
        		if(!chmod($path, 0777)){
            	    return false;
            	}
        	}
        	//pr($path);
        	
        	if(is_writable($path)){
        		return true;
        	}
        }catch (Exception $ex){
    	    return false;
    	}
    	return false;
    }
    
    public static function getSubUserFolder($userId)
    {
        $folderName = array(
        		$userId % 100,
        		floor(($userId % 10000) / 100),
        );
        
        $endFolder = '/' . $folderName[0] . '/' . $folderName[1];
        return $endFolder;
    }
    
    /**
     * @param string $rootFolder, folder where to save all userFolder
     * @param integer $userId
     *
     * @return string
     */
    public static function prepareFolder($rootFolder, $userId)
    {
    	$folderName = array(
    			$userId % 100,
    			floor(($userId % 10000) / 100),
    	);
    
    	$endFolder = $rootFolder . '/' . $folderName[0] . '/' . $folderName[1];
    
    	$path = $rootFolder;
    	foreach ($folderName as $name){
    		$path = $path . '/' . $name;
    		if(!self::checkFolder($path)){
    			throw new Exception('Cannot create folder: ' . $path);
    			return false;
    		}
    	}
    
    	return $endFolder;
    }
    
    public static function getSizeConfig()
    {
        return SGN_Application::getConfig('sgn', 'profile', 'profilePicture');
    }

    /**
     * Check if folders for user's picture are exist, otherwise, create them.
     * Each user has a folder named by their userId, it's children is named by picture size.
     * 
     * @return true if success, otherwise, return false.
     * 
     * @param $userId
     */
    public static function prepareUserFolder($userId)
    {
    	//prepare temp directory.
    	$config = SGN_Application::getConfig('sgn', 'settings', 'upload');
    	$tmpdir = ROOT_PATH . '/' . $config->tmpdir;
//     	pr($tmpdir, 0);
//     	pr(self::checkFolder($tmpdir), 0);
    	if(!self::checkFolder($tmpdir)){
    	    return false;
    	}
    	
    	$config = SGN_Application::getConfig('sgn', 'settings', 'profile');
    	//prepare user profilepicture directory
    	$userDir = ROOT_PATH . '/' . $config->profilepicture->location;
    	if(!self::checkFolder($userDir)){
    	    return false;
    	}
    	
    	$originFolder = self::prepareFolder(ROOT_PATH . '/' . $config->profilepicture->originLocation, $userId);
    	
    	$dir = $originFolder . '/' . $userId;
    	if(!self::checkFolder($dir)){
    	    return false;
    	}
    	
//     	$sizeConfig = SGN_Application::getConfig('sgn', 'profile', 'profilePicture');
//     	foreach ($sizeConfig as $size) {
//     	    $sizeDir = $dir . '/' . $size->dir;
//         	if(!self::checkFolder($sizeDir)){
//         	    return false;
//         	}
//     	}
    	
    	return $dir;
    }
    
//     public function resize($sizeConfig, $oldFileName, $path, $newName)
//     {
//         $image_info = getimagesize($oldFileName);
//         $image_type = $image_info[2];
//         $originalWidth = $image_info[0];
//         $originalHeight = $image_info[1];
//         $availableWidth = $originalWidth;
//         $availableHeight = $originalHeight;
//         $startx = 0;
//         $starty = 0;
        
//         if( $image_type == IMAGETYPE_JPEG ) {
//         	$oldImg = imagecreatefromjpeg($oldFileName);
//         } elseif( $image_type == IMAGETYPE_GIF ) {
//         	$oldImg = imagecreatefromgif($oldFileName);
//         } elseif( $image_type == IMAGETYPE_PNG ) {
//         	$oldImg = imagecreatefrompng($oldFileName);
//         } else {
//         	unlink($oldFileName);
//         	return false;
//         }
        
        		
//     	$saveSucc = false;
//         foreach ($sizeConfig as $size) {
//         	$width = isset($size['width']) ? $size['width'] : 0;
//         	$height = isset($size['height']) ? $size['height'] : 0;
//         	if($width == 0 || $height == 0)
//         		continue;
//         	if(($originalWidth/$width) > ($originalHeight/$height)){
//         		$availableWidth = ($originalHeight * $width) / $height;
//         		$startx = ($originalWidth - $availableWidth) / 2;
//         	} else {
//         		$availableHeight = ($originalWidth * $height) / $width;
//         		$starty = ($originalHeight - $availableHeight) / 2;
//         	}
//         	//make a resized copy, $image_info[0] and [1] is old width and height
//         	$newImage = imagecreatetruecolor($width, $height);
//         	imagecopyresampled($newImage, $oldImg, 0, 0, $startx, $starty, $width, $height, $availableWidth, $availableHeight);
//         	//Save to disk
//         	if($size['dir']) {
//         		if( $image_type == IMAGETYPE_JPEG ) {
//         			$saveSucc = imagejpeg($newImage, $path . '/' . $size['dir'] . '/' . $newName);
//         		} elseif( $image_type == IMAGETYPE_GIF ) {
//         			$saveSucc = imagegif($newImage, $path . '/' . $size['dir'] . '/' . $newName);
//         		} elseif( $image_type == IMAGETYPE_PNG ) {
//         			$saveSucc = imagepng($newImage, $path . '/' . $size['dir'] . '/' . $newName);
//         		}
//         	} else {
//         		if( $image_type == IMAGETYPE_JPEG ) {
//         			$saveSucc = imagejpeg($newImage, $path . '/' . $newName);
//         		} elseif( $image_type == IMAGETYPE_GIF ) {
//         			$saveSucc = imagegif($newImage, $path . '/' . $newName);
//         		} elseif( $image_type == IMAGETYPE_PNG ) {
//         			$saveSucc = imagepng($newImage, $path . '/' . $newName);
//         		}
//         	}
//         }
//         return $saveSucc;
//     }
    
    /**
     * Crop and resize image base on $sizeConfig
     * 
     * @param array $sizeConfig
     * @param string $oldFileName
     * @param string $path
     * @param string $newName
     */
    public function resize($sizeConfig, $oldFileName, $path, $newName)
    {
        try {
        	$image = new Imagick($oldFileName);
        	
        	$originalWidth = $image->getimagewidth();
        	$originalHeight = $image->getimageheight();
        	$availableWidth = $originalWidth;
        	$availableHeight = $originalHeight;
        	$startx = 0;
        	$starty = 0;
        
        	$saveSucc = false;
        	foreach ($sizeConfig as $size) {
        		$width = isset($size['width']) ? $size['width'] : 0;
        		$height = isset($size['height']) ? $size['height'] : 0;
        		if($width == 0 || $height == 0)
        			continue;
        		if(($originalWidth/$width) > ($originalHeight/$height)){
        			$availableWidth = ($originalHeight * $width) / $height;
        			$startx = ($originalWidth - $availableWidth) / 2;
        		} else {
        			$availableHeight = ($originalWidth * $height) / $width;
        			$starty = ($originalHeight - $availableHeight) / 2;
        		}
        		
        		//make a resized copy, $image_info[0] and [1] is old width and height
            	$copyOfImage = clone $image;
            	$copyOfImage->cropimage($availableWidth, $availableHeight, $startx, $starty);
            	$copyOfImage->resizeImage($width, $height, imagick::FILTER_UNDEFINED, 1);
        		//Save to disk
        		if($size['dir']) {
                	$saveSucc = $copyOfImage->writeimage($path . '/' . $size['dir'] . '/' . $newName);
        		} else {
        			$saveSucc = $copyOfImage->writeimage($path . '/' . $newName);
        		}
        	}
        } catch (Exception $ex){
        
        }
        
    	return $saveSucc;
    }
    
//     public function uploadFrom
    
    /**
     * Get picture from $url and save in $path with $newName
     *  
     * @param string $url
     * @param string $path
     * @param string $newName
     * 
     * @return boolean
     */
    public function uploadFromUrl($url, $path, $name)
    {
        $config = SGN_Application::getConfig('sgn', 'settings', 'upload');
        
        return file_put_contents($path . '/' . $name, file_get_contents($url));
    }
    
    /**
     * Get a picture from client corressponding to $controlName, make some copies due to $sizeConfig and save them in $path
     * 
     * @param array $sizeConfig
     * @param string $controlName
     * @param string $path
     * @param string $newName
     * 
     * @return boolean
     */
    public function receiveAndResize($sizeConfig, $controlName, $path, $newName = '')
    {
    	$config = SGN_Application::getConfig('sgn', 'settings', 'upload');
    	if(!$newName){
        	$originalFileName = $this->getEncodedFileName($controlName);
    		$newName = $originalFileName;
    	}
//     	if(file_exists(ROOT_PATH . '/' . $config->tmpdir . $newName)){
//     		if(!@unlink(ROOT_PATH . '/' . $config->tmpdir . $newName)) 
//     			return false;
//     	}

    	$originLocation = str_replace('profilepic', 'profilepic_original', $path) . '/';
    	if($this->receive($controlName, $originLocation, $newName)){
		    
//     		$oldFileName = ROOT_PATH . '/' . $config->tmpdir . $originalFileName;
            $oldFileName=  $originLocation . $newName;
            
        	//save resized copy
		    $saveSucc = $this->resize($sizeConfig, $oldFileName, $path, $newName);
	    	
		    //unlink($oldFileName);
    		return $saveSucc;
    	}
    	return false;
    }
    
    public function getEncodedFileName($controlName)
    {
    	return str_replace(' ', '_', $this->adapter->getFileName($controlName, false));
    }
    /**
     * @return array
     */
    public function getMessages()
    {
    	return $this->adapter->getMessages();
    }
    
    public function setRenameIfDuplicate($value)
    {
    	$this->renameIfDuplicate = $value;
    }
    
	public function getRenameIfDuplicate($value)
    {
    	return $this->renameIfDuplicate;
    }
    
    public function clearValidators()
    {
    	$this->adapter->clearValidators();
    }
    
    public function removeValidator($name)
    {
    	$this->adapter->removeValidator($name);
    }
    
    public function setFileType($types)
    {
    	$extensionValidator = new Zend_Validate_File_Extension($types);
        $this->adapter->addValidator($extensionValidator, false);
    }
    
    public function setMaxSizeOnly($max)
    {
    	$sizeValidator = new Zend_Validate_File_Size(array ('max' => $max));
        $this->adapter->addValidator($sizeValidator, false);
    }
    
    public function setMinSizeOnly($min)
    {
    	$sizeValidator = new Zend_Validate_File_Size(array ('min' => $min));
        $this->adapter->addValidator($sizeValidator, false);
    }
    
    public function setMinAndMax($min, $max)
    {
    	$sizeValidator = new Zend_Validate_File_Size(array ('min' => $min, 'max' => $max));
        $this->adapter->addValidator($sizeValidator, false);
    }
}